﻿
#region 作者和版权
/*************************************************************************************
* CLR 版本: 4.0.30319.42000
* 类 名 称: UserToken
* 机器名称: SUNTIA-QL
* 命名空间: ServerFramework.Net.Tcp
* 文 件 名: UserToken
* 创建时间: 2015/9/23 10:50:21
* 作 者: 乔龙 Qiaolong
* 版 权: UserToken说明：本代码版权归乔龙所有，使用时必须带上乔龙网站地址 All Rights Reserved (C) 2015 - 2013
* 签 名: To be or not, it is not a problem !
* 网 站: http://www.suntia.net
* 邮 箱: qiaolong306@qq.com 
* 唯一标识： b1327fb0-14cd-4bd2-aefd-d46e7a85404c 
*
* 登录用户: simida
* 所 属 域: SUNTIA-QL

* 创建年份: 2015
* 修改时间:
* 修 改 人:
* 
************************************************************************************/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using ServerFramework.Tools;
using ServerFramework.Net.Msg;


namespace ServerFramework.Net.Tcp
{
    /// <summary>
    /// 用户连接信息对象
    /// </summary>
    public class UserToken:ISender
    {
        public TcpServer server;
        public int linkId;
        /// <summary>
        /// 用户连接
        /// </summary>
        public Socket conn;
        //用户异步接收网络数据对象
        public SocketAsyncEventArgs receiveSAEA;
        //用户异步发送网络数据对象
        public SocketAsyncEventArgs sendSAEA;

        private List<byte> _readCache = new List<byte>();
        private Queue<byte[]> _writeQueue = new Queue<byte[]>();

        /// <summary>
        /// 激活的时间，用于心跳检测
        /// </summary>
        public DateTime ActiveTime;

        private bool _isReading = false;
        private bool _isWriting = false;

        public UserToken()
        {
            receiveSAEA = new SocketAsyncEventArgs();
            sendSAEA = new SocketAsyncEventArgs();
            receiveSAEA.UserToken = this;
            sendSAEA.UserToken = this;
            //设置接收对象的缓冲区大小
            receiveSAEA.SetBuffer(new byte[1024], 0, 1024);
            ActiveTime = DateTime.Now;
        }

        public void Send(byte[] data)
        {
            if (conn == null)
            {
                //此连接已经断开了
                server.ClientClose(this, "调用已经断开的连接");
                return;
            }
            _writeQueue.Enqueue(data);
            if (!_isWriting)
            {
                _isWriting = true;
                onWrite();
            }
        }

        public void Writed()
        {
            //与onData尾递归同理
            onWrite();
        }

        public void onWrite()
        {
            //判断发送消息队列是否有消息
            if (_writeQueue.Count == 0) { _isWriting = false; return; }
            //取出第一条待发消息
            byte[] buff = _writeQueue.Dequeue();
            //设置消息发送异步对象的发送数据缓冲区数据
            sendSAEA.SetBuffer(buff, 0, buff.Length);
            //开启异步发送
            bool result = conn.SendAsync(sendSAEA);
            //是否挂起
            if (!result)
            {
                server.ProcessSend(sendSAEA);
            }
        }

        /// <summary>
        /// 读取数据
        /// </summary>
        /// <param name="data"></param>
        public void Recv(byte[] data)
        {
            //将消息写入缓存
            _readCache.AddRange(data);
            if (!_isReading)
            {
                _isReading = true;
                onData();
            }
        }

        //缓存中有数据处理
        void onData()
        {
            //解码消息存储对象
            byte[] buff = null;
            //当粘包解码器存在的时候 进行粘包处理
            buff = MsgPacket.SplitPacket(ref _readCache);
            //消息未接收全 退出数据处理 等待下次消息到达
            if (buff == null) { _isReading = false; return; }
            MsgPacket msg = MsgPacket.SplitPacket(this, buff, 0, buff.Length);
            //排除心跳包 通知应用层 有消息到达
            if (msg.msgId != SystemMsgID.heartId)
            {
                try
                {
                    server.onRecvMessage(msg);
                }
                catch (Exception e)
                {
                    Log.WriteLog(ELogLevel.LOG_ERROR, e);
                }
            }
            //尾递归 防止在消息处理过程中 有其他消息到达而没有经过处理
            onData();
        }

      

        public void Close()
        {
            try
            {
                _writeQueue.Clear();
                _readCache.Clear();
                _isReading = false;
                _isWriting = false;
                conn.Shutdown(SocketShutdown.Both);
                conn.Close();
                conn = null;
            }
            catch (Exception)
            {
               // Log.WriteLog(ELogLevel.LOG_ERROR, e.Message);
            }
        }
    }
}


